#ifndef __ZSOCKET_H_
	#define __ZSOCKET_H_
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include "DEBUG.h"


#define RECEIVE_BUFFSIZE 1024*8
#define MAXPENDING 256
int
NewTCPSocket();
struct sockaddr_in
NewTCPAddr(const char * host,int port);
void
SendAndRecv(
		const char * host,
		int port,
		const void * senddata,
		size_t senddatalen,
		void * recv_buffer,
		size_t * recvlen
		);
char *
nslkup(const char * host_name){
	struct hostent *host;
	struct in_addr h_addr;
	if ((host = gethostbyname(host_name)) == NULL){
		fprintf(stderr,"nslookup failed on '%s' \n",host_name);
		exit(-1);
	}//if
	h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
	return inet_ntoa(h_addr);
}//nslookup()

int
Socket(int family, int type, int protocol){
	int sock;
	if ((sock = socket(family,type,protocol)) < 0){
		Die("Failed to create socket");
	}
	return sock;
}

int
Connect(int socket, const struct sockaddr * addr, socklen_t size){
	int e;
	if ((e = connect(socket, addr, size)) < 0){
		Die("Failed to connect with server");
	}
	return e;
}
int
Send(int socket, const char * data, long datalen, int flag){
	int e;
	if ( (e = send(socket,data,datalen,flag)) != datalen){
		Die("Mismatch in number of sent bytes");
	}
	return e;
}
int
Recv(int socket, void * buffer, socklen_t size,int flag){
	void * ptr = buffer;
	int received = 0,
		bytes    = -1;
	while ((bytes = recv(socket, ptr, size - received, flag)) > 0){
		received += bytes;
		ptr 	 += bytes;
	}
	return received;
}
int
Bind(int socket,const struct sockaddr * addr, socklen_t size){
	int e;
	if ((e = bind(socket, addr, size)) < 0) {
		Die("Failed to bind the server socket");
	}
	return e;
}
int
Listen(int socket, int maxpending){
	int e;
	if ((e = listen(socket, maxpending)) < 0) {
		Die("Failed to listen");
	}
	return e;
}
int
Accept(int socket, struct sockaddr * addr, socklen_t * size){
	int sock;
	if ((sock = accept(socket, addr, size)) < 0) {
		Die("Failed to accept client connection");
	}
	return sock;
}
int
Close(int socket){
	return close(socket);
}
int
NewTCPSocket(){
	return Socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
}
struct sockaddr_in
NewTCPAddr(const char * host,int port){
	struct sockaddr_in server;
	memset(&server,0,sizeof(struct sockaddr_in));
	server.sin_family		= AF_INET;
	server.sin_port 		= htons(port);
	inet_pton(AF_INET, nslkup(host),&(server.sin_addr));
	return server;
}
void
SendAndRecv(
		const char * host,
		int port,
		const void * senddata,
		size_t senddatalen,
		void * recv_buffer,
		size_t * recvlen
		){
	struct sockaddr_in server= NewTCPAddr(host,port);
	int sock = Socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    DEBUG("sock = %d",sock);

	/*Connect and send*/
	Connect(sock,(struct sockaddr*)&server,sizeof(server));
	Send(sock,senddata,senddatalen,0);
	*recvlen = Recv(sock,recv_buffer,RECEIVE_BUFFSIZE,0);
}

#endif
